
(function(window) {

	/**
	 * Various useful bits of functionality.
	 * @namespace Utilities
	 */
	var Utilities = {};
	Types.exportSymbol("Utilities", Utilities);

	var LOREM = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ";
	var LOREM_LEN = LOREM.length;
	
	Utilities.lorem = function(length) {
		var string = "";
		var count = length / LOREM_LEN;
		var remainder = length % LOREM_LEN;
		for(var i = 0; i < count; i++) {
			string += LOREM;
		}
		string += LOREM.substring(0, remainder);
		
		return string;
	};
	
	/**
	 * Push the second array into the first array.
	 * 
	 */
	Utilities.pushArray = function pushArray(target, source) {
		target.push.apply(target, source);
	};
	
	Utilities.isDefined = function isDefined(a) {
		if ( typeof a == "undefined") {
			return false;
		} else {
			return true;
		}
	};
	
	/** 
	 * A utility function to make default values easier to assign. If the specified value is defined and not null, it
	 *   is returned. Otherwise, the specified default value is returned.
	 * 
	 * @memberOf Utilities
	 * @name valueOrDefault
	 * 
	 * @property value the value to check
	 * @property defaultValue the value return if value is not defined.
	 * @returns {mixed} the first argument, if defined, otherwise the second argument.
	 * @expose 
	 */
	Utilities.valueOrDefault = function valueOrDefault(value, defaultValue) {
		if (Utilities.isDefined(value)) {
			return value;
		} else {
			return defaultValue;
		}
	};

	/**
	 * Returns the value of the query string parameter on the current page, or null
	 *   if no such param exists.
	 * 
     * @param {Object} parameterName
     * @expose
	 */
	Utilities.getParameterByName = function (parameterName) {
		if(! window) {
			return;
		}
		if(! window.location) {
			return;
		}
		if(! window.location.href) {
			return;
		}
		parameterName = parameterName.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
		var regexS = "[\\?&]" + parameterName + "=([^&#]*)";
		var regex = new RegExp(regexS);
		var results = regex.exec(window.location.href);
		if (results == null) {
			return null;
		} else {
			return decodeURIComponent(results[1].replace(/\+/g, " "));
		}
	};
	
	/**
	 * 
     * @param {number} index the index in the path to return
     * @expose
	 */
	Utilities.getPathPart = function (index) {
		if(! window) {
			return;
		}
		if(! window.location) {
			return;
		}
		if(! window.location.pathname) {
			return;
		}
		
		var pathParts = window.location.pathname.substring(1).split("/");
		return pathParts[index];
	};

	
	Utilities.getCookie = function getCookie(c_name) {
		var i, x, y, ARRcookies = document.cookie.split(";");
		for ( i = 0; i < ARRcookies.length; i++) {
			x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("="));
			y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
			x = x.replace(/^\s+|\s+$/g, "");
			if (x == c_name) {
				return unescape(y);
			}
		}
	}
	
	/**
	 * This is good for returning a clickable stackframe for use in debugging.
	 *   if run without arguments or with a depth of 0, it will return the stack
	 *   frame from where it is called.
	 * 
	 * If called with a positive value, it will return the frame from further up 
	 *   the stack. For example, if you want to return the frame from the method
	 *   that called some method you are writing, use a depth of one.  
	 * 
     * @param {Object} depth
     * @expose
	 */
	Utilities.getStackFrame = function getStackFrame(depth) {
		
		function getErrorObject() {
			try {
				throw new Error("")
			} catch(err) {
				return err;
			}
		}

		depth = Utilities.valueOrDefault(depth, 0);
		var err = getErrorObject();
		
		if(! err) {
			return "(no error object available)";
		} else if(! err.stack) {
			return "(no stack array available)";
		}
		
		var stack = err.stack.split("\n");
		var caller_line = stack[4 + depth];
		var index = caller_line.indexOf("at ");
		var clean = caller_line.slice(index + 2, caller_line.length);
		index = clean.lastIndexOf(":");
		clean = clean.substring(0, index);
		return clean;
	};
	
})(this);
